# 鹿鼎记 · 韦小宝,丽春院、天地会、入皇宫等五个场景,搭配不同剧情讲解多线程和锁,真香!

作者:小傅哥
博客:https://bugstack.cn (opens new window)
原文:https://mp.weixin.qq.com/s/gI01lKzvpmhPr_Z-jRQysQ (opens new window)

沉淀、分享、成长,让自己和他人都能有所收获!😄

# 一、前言

学习路径决定学习效果!

有时候很多看似复杂的知识,其实并没有多复杂,只不过你找到的那份资料把知识讲复杂了。为什么这么说呢🤔?

学习知识可以想象成是一个从开头接触结尾把知识吸纳的过程,在这个过程中会有一些知识路径行走经历。那么不同的资料就是带着你在走这条知识路径,只不过有些资料容易绕路或者难走(路也跟车有关系,有些路适合客车🚌、有些路适合轿车🚗)。而当你找到一份非常不错并且适合自己的资料时,就会有一种酣畅、通透的感觉,不会感觉学起来多复杂,同时不仅学会了也理解了核心本质。这份资料在你手里就是,车速有点快、系好安全带

所以,能找到最好的资料也是学习过程中,非常重要的一个点。你的检索能力越强,你就会越容易找到最合适你的资料。

接下来小傅哥就带你进入鹿鼎记 · 韦小宝多线程和锁的故事路线,感受逗B的学习路线!

# 二、韦小宝与多线程

图 12-1 鹿鼎记·韦小宝,多线程恶搞例子

小傅哥选取了五个鹿鼎记场景,融入进去不同的多线程使用,包括:丽春院,说书天地会,香主招收杂役,入宫皇上、建宁,比武七个老婆,隐居,这样五个场景。相信你看完后,一定会记住每个线程的使用!

# 1. 丽春院,说书

图 12-2 丽春院,说书

public class SynchronizedTest {

    private static ExecutorService 丽春院 = Executors.newFixedThreadPool(10);

    private static volatile boolean 老鸨 = false;

    public static class 客官 implements Runnable {

        private String 姓名;

        public 客官(String 姓名) {
            this.姓名 = 姓名;
        }

        @Override
        public void run() {
            try {
                清倌(姓名);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static synchronized void 清倌(String 姓名) throws InterruptedException {
        while (true){
            System.out.println("韦春花与" + 姓名 + "喝茶、吟诗、做对、聊风月!");
            if (老鸨){
                System.out.println("老鸨敲门:时间到啦!\r\n");
                老鸨 = false;
                break;
            }
            Thread.sleep(1000);
        }

    }

    private static List<String> list = Arrays.asList("鳌大人", "陈近南", "海大富");

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            丽春院.execute(new 客官(list.get(i)));
            Thread.sleep(3000);
            老鸨 = true;
        }
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  • 场景:韦小宝在丽春院打杂说书时,常有一些大佬(鳌大人陈近南海大富)前来与清倌吟诗、做对、聊风月。但由于大家都欣赏其中一个叫韦春花的清倌,所以需要排队。
  • 知识:使用 synchronized 锁,和 volatile 可见性,不断的实例化客官加入线程池,等待与清倌聊天。还可以使用wait()、notify()来实现这一效果过程
  • 测试结果
韦春花与鳌大人喝茶、吟诗、做对、聊风月!
韦春花与鳌大人喝茶、吟诗、做对、聊风月!
韦春花与鳌大人喝茶、吟诗、做对、聊风月!
韦春花与鳌大人喝茶、吟诗、做对、聊风月!
老鸨敲门:时间到啦!

韦春花与陈近南喝茶、吟诗、做对、聊风月!
韦春花与陈近南喝茶、吟诗、做对、聊风月!
韦春花与陈近南喝茶、吟诗、做对、聊风月!
韦春花与陈近南喝茶、吟诗、做对、聊风月!
老鸨敲门:时间到啦!

韦春花与海大富喝茶、吟诗、做对、聊风月!
韦春花与海大富喝茶、吟诗、做对、聊风月!
韦春花与海大富喝茶、吟诗、做对、聊风月!
韦春花与海大富喝茶、吟诗、做对、聊风月!
老鸨敲门:时间到啦!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2. 天地会,香主

图 12-3 天地会,香主

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        List<String> list = Arrays.asList("总舵主,陈近南", "莲花堂香主,蔡德忠",
                "洪顺堂香主,方大洪",
                "家后堂香主,马超兴",
                "参太堂香主,胡德帝",
                "宏化堂香主,李式开",
                "青木堂香主,韦小宝",
                "赤火堂香主,古至中",
                "玄水堂香主,林永超",
                "黄土堂香主,姚必达");

        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            int idx = i;
            exec.execute(() -> {
                try {
                    System.out.println("天地会核心十堂核心成员,高层会议,成员:" + list.get(idx) + " 入场");
                    Thread.sleep(3000);
                } catch (Exception ignore) {
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await();
        System.out.println("天地会,核心成员到齐。开会讨论谁入宫,偷取四十二章经!「内定韦香主」");
        exec.shutdown();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  • 场景:韦小宝在丽春院营救陈近南后,加入了天地会还当上了青木堂韦香主,与其他九位香主齐名:洪顺堂、家后堂、参太堂、宏化堂、赤火堂、玄水堂、黄土堂。这也是天地会的核心成员,他们经常定期开会。这不,就开会讨论由谁入宫偷取四十二章经,其实已经内定了韦香主·韦小宝。
  • 知识CountDownLatch 门栓效果,满足一定人数就开船、摇摆锤、过山车🎢。那么开会的效果也是使用这个锁来实现,满足10个人以后,关门开始。
  • 测试结果
天地会核心十堂核心成员,高层会议,成员:总舵主,陈近南 入场
天地会核心十堂核心成员,高层会议,成员:莲花堂香主,蔡德忠 入场
天地会核心十堂核心成员,高层会议,成员:洪顺堂香主,方大洪 入场
天地会核心十堂核心成员,高层会议,成员:家后堂香主,马超兴 入场
天地会核心十堂核心成员,高层会议,成员:参太堂香主,胡德帝 入场
天地会核心十堂核心成员,高层会议,成员:宏化堂香主,李式开 入场
天地会核心十堂核心成员,高层会议,成员:青木堂香主,韦小宝 入场
天地会核心十堂核心成员,高层会议,成员:赤火堂香主,古至中 入场
天地会核心十堂核心成员,高层会议,成员:玄水堂香主,林永超 入场
天地会核心十堂核心成员,高层会议,成员:黄土堂香主,姚必达 入场
天地会,核心成员到齐。开会讨论谁入宫,偷取四十二章经!「内定韦香主」
1
2
3
4
5
6
7
8
9
10
11

# 3. 招收杂役,入宫

图 12-4 招收杂役,入宫

public class ReentrantLockTest {

    private static ReentrantLock lock = new ReentrantLock(true);

    private static List<String> list = Arrays.asList("路人甲", "路人乙", "路人丙", "路人丁", "路人戊", "路人己", "路人庚", "路人壬", "路人癸", "韦小宝");

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            int idx = i;

            new Thread(() -> {
                try {
                    招收杂役(list.get(idx));
                } catch (InterruptedException ignore) {
                }
            }).start();

            if (idx == 9) {
                new Thread(() -> {
                    招收太监(list.get(idx));
                }).start();
            }
        }
    }

    public static void 招收杂役(String name) throws InterruptedException {
        lock.lock();
        try {
            while (true) {
                System.out.println(name + ",排队等待进宫当杂役...");
                Thread.sleep(1000);
            }
        } finally {
            lock.unlock();
        }
    }

    public static void 招收太监(String name) {
        System.out.println(name + ",进宫当太监,不用排队!");
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • 场景:在被坑作为入宫人选好后,小宝来到了招募杂役的地方,一看排队好长。灵机一动跑到了旁边,*这边没有人排队呀!*就立马冲了进去。我们在案例中采用公平锁排队的方式来体现这一场景。
  • 知识ReentrantLock,公平锁排队,在代码中需要显示的开启锁和关闭锁。
  • 测试结果
路人甲,排队等待进宫当杂役...
韦小宝,进宫当太监,不用排队!
路人甲,排队等待进宫当杂役...
路人甲,排队等待进宫当杂役...
路人甲,排队等待进宫当杂役...
路人甲,排队等待进宫当杂役...
路人甲,排队等待进宫当杂役...
1
2
3
4
5
6
7

# 4. 皇上、建宁,比武

图 12-5 皇上、建宁,比武

public class ReentrantReadWriteLockTest {

    private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static final Lock readLock = readWriteLock.readLock();
    private static final Lock writeLock = readWriteLock.writeLock();

    private static Deque<String> deque = new ArrayDeque<>();

    public static String get() {
        readLock.lock();
        try {
            return deque.poll();
        } finally {
            readLock.unlock();
        }
    }

    public static void put(String value) {
        writeLock.lock();
        try {
            deque.add(value);
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {
        new Thread(() -> {
            while (true) {
                put("小擒拿");
                put("抓乃龙抓手");
                put("下脚绊");
                put("大别子");
                put("锁喉");
                put("扣眼珠子");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ignore) {
                }
            }
        }).start();

        new Thread(() -> {
            while (true) {
                System.out.println("韦小宝与皇上比武出招:" + get());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ignore) {
                }
            }
        }).start();
    }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  • 场景:在海大富的帮助下蒙混进宫偷四十二章经时,不小心被建宁公主发现,为此引来这样一段打斗比武的场景。小宝不会武功,每天学会点再比试点,因此我们这里使用读写锁来模拟。写锁相当于传授知识、读锁相当于使用知识
  • 知识ReentrantReadWriteLock 关于读写锁的使用。
  • 测试结果
韦小宝与皇上比武出招:小擒拿
韦小宝与皇上比武出招:抓乃龙抓手
韦小宝与皇上比武出招:下脚绊
韦小宝与皇上比武出招:大别子
韦小宝与皇上比武出招:锁喉
韦小宝与皇上比武出招:扣眼珠子
韦小宝与皇上比武出招:小擒拿
韦小宝与皇上比武出招:抓乃龙抓手
韦小宝与皇上比武出招:下脚绊
韦小宝与皇上比武出招:大别子
韦小宝与皇上比武出招:锁喉
韦小宝与皇上比武出招:扣眼珠子
韦小宝与皇上比武出招:小擒拿
韦小宝与皇上比武出招:抓乃龙抓手
韦小宝与皇上比武出招:下脚绊
韦小宝与皇上比武出招:大别子
韦小宝与皇上比武出招:锁喉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 5. 七个老婆,隐居

图 12-6 七个老婆,隐居

public class SemaphoreTest {

    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("韦小宝");
        list.add("阿珂");
        list.add("双儿");
        list.add("曾柔");
        list.add("建宁公主");
        list.add("沐建屏");
        list.add("方怡");
        list.add("苏荃");

        Semaphore semaphore = new Semaphore(4, true);
        for (int i = 0; i < 8; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    String user = list.remove(new Random().nextInt(list.size()));
                    System.out.println("韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:" + user);
                    Thread.sleep(3000L);
                } catch (InterruptedException ignore) {
                } finally {
                    semaphore.release();
                }
            }).start();
        }

    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  • 场景:经历了风风雨雨的小宝,最后决定和老婆们过起快乐的隐居生活。我们这里模拟隐居桃园后,每天打打麻将、练练武术,凑够一桌四人。这里我们使用信号量锁 Semaphore,一次凑够四个人就够一桌麻将的人。随机抽取四个人
  • 知识Semaphore 信号量锁的使用
  • 测试结果
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:曾柔
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:苏荃
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:双儿
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:阿珂

韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:方怡
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:韦小宝
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:建宁公主
韦小宝带着七个老婆,过着桃园生活。每天打打麻将、练练武术。麻将四人桌:沐建屏
1
2
3
4
5
6
7
8
9

# 三、总结

  • 在鹿鼎记的场景中我们串进去了各个多线程的使用案例,分别包括不同锁:SynchronizedCountDownLatchReentrantLockReentrantReadWriteLockSemaphore
  • 很多时候如果在学习的过程中,如果能找到一些非常适合的例子,那么对于知识点的学习是非常快的也能有深刻的印象。
  • 好嘞,这个案例就写完了,感谢支持。同时,这里面的各个场景中的多线程和锁也可以有不同的方式的使用来实现每个场景的效果,可以自行尝试。